package com.flyqiu.flow.core.var;

import com.flyqiu.flow.api.context.FlyQiuFlowGlobalContext;
import com.flyqiu.flow.api.script.FlyQiuFlowVarSerializeManage;
import com.flyqiu.flow.api.script.IVariableScope;
import com.flyqiu.flow.model.entity.base.Variable;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 变量作用域
 */
public class VariableScope implements IVariableScope {

    private Map<String, Variable> variableMap;

    private final Map<String, Object> varMap = new HashMap<>();
    private final FlyQiuFlowVarSerializeManage varSerializeManage;

    private final List<IVariableScope> list = new ArrayList<>();


    public VariableScope(FlyQiuFlowGlobalContext globalContext, IVariableScope subVariableScope) {
        this(globalContext.getFlowVarSerializeManage());
        variableMap = new HashMap<>();
        append(subVariableScope);
    }

    public VariableScope(FlyQiuFlowVarSerializeManage varSerializeManage) {
        this.varSerializeManage = varSerializeManage;
        variableMap = new HashMap<>();
    }


    public VariableScope(FlyQiuFlowVarSerializeManage varSerializeManage, Map<String, Variable> variableMap) {
        if (variableMap == null) {
            variableMap = new HashMap<>();
        }
        this.variableMap = variableMap;
        this.varSerializeManage = varSerializeManage;
    }

    public VariableScope(FlyQiuFlowVarSerializeManage varSerializeManage, Collection<Variable> variables) {
        this(varSerializeManage);
        if (variables == null) {
            variables = new ArrayList<>();
        }
        variableMap = variables.stream().collect(Collectors.toMap(Variable::getVarName, e -> e, (e1, e2) -> e1));
    }


    @Override
    public void append(IVariableScope variableScope) {
        if (variableScope == null) return;
        list.add(variableScope);


    }

    @Override
    public void remove(IVariableScope targetVariableScope) {
        list.remove(targetVariableScope);
    }


    @Override
    public Map<String, Variable> getVariableMap() {
        List<Variable> variables = getVariables();
        return variables.stream().collect(Collectors.toMap(Variable::getVarName, e -> e, (e1, e2) -> e1));
    }

    @Override
    public List<Variable> getVariables() {
        List<Variable> result = new ArrayList<>();
        for (int i = list.size() - 1; i >= 0; i--) {
            result.addAll(list.get(i).getVariables());
        }
        result.addAll(variableMap.values());
        return result;
    }

    @Override
    public void addTempVar(String varName, Object varVal) {
        varMap.put(varName, varVal);
    }

    @Override
    public boolean hasVar(String varName) {
        for (int i = list.size() - 1; i >= 0; i--) {
            if (list.get(i).hasVar(varName)) {
                return true;
            }
        }
        if (varMap.containsKey(varName)) {
            return true;
        }
        return variableMap.containsKey(varName);
    }

    @Override
    public Object getVal(String varName) {
        for (int i = list.size() - 1; i >= 0; i--) {
            if (list.get(i).hasVar(varName)) {
                return list.get(i).getVal(varName);
            }
        }

        if (varMap.containsKey(varName)) {
            return varMap.get(varName);
        }
        if (!variableMap.containsKey(varName)) {
            return null;
        }
        Variable variable = variableMap.get(varName);
        String valType = variable.getValType();
        Object deserialize = varSerializeManage.deserialize(valType, variable.getVarValue());
        varMap.put(varName, deserialize);
        return deserialize;
    }

    @Override
    public long varCount() {
        return variableMap.size();
    }


}
